package com.quectel.mobile.controller.partybuilding;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.constant.core.partyeducationexam.PartyEducationExamConstants;
import com.quectel.constant.core.partyeducationtraining.TrainingConstants;
import com.quectel.constant.core.partyeducationtraining.TrainingItemConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.module.partybuilding.dto.PartyPersonDto;
import com.quectel.core.module.partyeducationexam.dto.PartyEducationTrainingExamDto;
import com.quectel.core.module.partyeducationexam.dto.PartyEducationTrainingExamPersonDto;
import com.quectel.core.module.partyeducationexam.dto.ref.ExamRefPersonDto;
import com.quectel.core.module.partyeducationexam.service.PartyEducationTrainingExamPersonService;
import com.quectel.core.module.partyeducationtraining.dto.*;
import com.quectel.core.module.partyeducationtraining.dto.ref.TrainingItemRefConcourseItemDto;
import com.quectel.core.module.partyeducationtraining.dto.ref.TrainingRefConcourseDto;
import com.quectel.core.module.partyeducationtraining.service.*;
import com.quectel.mobile.controller.BaseController;
import com.quectel.mobile.util.SessionHolder;
import com.quectel.mobile.vo.partybuilding.TrainingItemVo;
import com.quectel.mobile.vo.training.CommentAppraiseReqVo;
import com.quectel.mobile.vo.training.ExperienceAppraiseReqVo;
import com.quectel.mobile.vo.training.TrainingItemStudyReqVo;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @email ryan.ran@quectel.com
 * @date 2022/5/23 17:31
 */
@RestController
@RequestMapping("partyBuildingTraining")
@Tag(name = "PartyBuildingTrainingController", description = "党员培训课程相关的api")
public class PartyBuildingTrainingController extends BaseController {

    @DubboReference
    private TrainingService trainingService;
    @DubboReference
    private TrainingPersonService trainingPersonService;
    @DubboReference
    private TrainingItemService trainingItemService;
    @DubboReference
    private TrainingItemPersonService trainingItemPersonService;
    @DubboReference
    private TrainingCommentService trainingCommentService;
    @DubboReference
    private TrainingExperienceService trainingExperienceService;
    @DubboReference
    private PartyEducationTrainingExamPersonService partyEducationTrainingExamPersonService;

    @GetMapping("list")
    @Operation(summary = "课程列表")
    public Response<Page<TrainingRefConcourseDto>> trainingList(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize,
            @Parameter(description = "状态 1待参加 2已结束") @RequestParam(required = false) Byte status,
            @Parameter(description = "课程名称") @RequestParam(required = false) String trainingName
    ) {
        // query training by person
        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        Request request = Request.configParams(Request.parseParams(httpServletRequest))
                .put(LambdaUtil.getFieldName(TrainingPersonDto::getPartyPersonId), partyPerson.getId())
                .put(LambdaUtil.getFieldName(TrainingDto::getPublishStatus), TrainingConstants.PublishStatusEnum.ON.getPublishStatus().toString());

        // 学习中 或 已结束
        if (status != null) {
            Map<String, Object> params = request.getParams();
            params.remove("status");
            if (status.equals((byte) 1)) {
                // 学习中
                params.put("isLearning", 1);
            } else {
                // 已结束认为是课程已结束的而非已完成学习
                params.put("hasEnded", 1);
            }
        }

        int total = trainingPersonService.queryTrainingTotal(request.getParams());
        List<TrainingRefConcourseDto> result = null;
        if (total > 0) {
            result = trainingPersonService.queryTrainingList(request.getParams());
        } else {
            result = new ArrayList<>();
        }

        Page<TrainingRefConcourseDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, result);
        return Response.<Page<TrainingRefConcourseDto>>ok().wrap(page);
    }

    @GetMapping("info/{trainingId}")
    @Operation(summary = "课程信息")
    public Response<TrainingRefConcourseDto> info(@PathVariable("trainingId") Long trainingId) {
        // select one by trainingId
        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        Map<String, Object> params = new HashMap<>();
        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getPartyPersonId), partyPerson.getId());
        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getTrainingId), trainingId);
        if (trainingPersonService.queryTrainingTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

//        TrainingDto trainingDto = trainingService.selectCacheById(trainingId);
        List<TrainingRefConcourseDto> trainingRefConcourseDtos = trainingPersonService.queryTrainingList(params);
        return Response.<TrainingRefConcourseDto>ok().wrap(trainingRefConcourseDtos.get(0));
    }

    @GetMapping("itemList")
    @Operation(summary = "课时信息列表")
    public Response<Page<TrainingItemVo>> trainingItemInfo(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize,
            @Parameter(description = "课程id") @RequestParam Long trainingId
    ) {
        // query trainingItem by trainingId
        // query trainingItem by personId and trainingId

        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        int total = trainingItemService.queryTotal(request.getParams());
        List<TrainingItemDto> result = null;
        if (total > 0) {
            result = trainingItemService.queryList(request.getParams());

            Map<String, Object> queryTrainingItemMap = new HashMap<>();
            queryTrainingItemMap.put(LambdaUtil.getFieldName(TrainingItemPersonDto::getPartyPersonId), partyPerson.getId());
            queryTrainingItemMap.put(LambdaUtil.getFieldName(TrainingItemDto::getTrainingId), trainingId);
            List<TrainingItemRefConcourseItemDto> concourseItemDtos
                    = trainingItemPersonService.queryTrainingItemList(queryTrainingItemMap);

            Map<Long, TrainingItemRefConcourseItemDto> studyStatusMap = new HashMap<>();
            for (TrainingItemRefConcourseItemDto concourseItemDto : concourseItemDtos) {
                studyStatusMap.put(concourseItemDto.getId(), concourseItemDto);
            }
            for (TrainingItemDto trainingItemDto : result) {
                TrainingItemRefConcourseItemDto trainingItemRefConcourseItemDto = studyStatusMap.get(trainingItemDto.getId());

                trainingItemDto.setStudyStatus(trainingItemRefConcourseItemDto == null
                        ? TrainingItemConstants.StudyStatusEnum.NOT_LEARNED.getStudyStatus()
                        : trainingItemRefConcourseItemDto.getStudyStatus());
                trainingItemDto.setStudyProgress(trainingItemRefConcourseItemDto == null
                        ? BigDecimal.ZERO
                        : trainingItemRefConcourseItemDto.getStudyProgress());
            }
        } else {
            result = new ArrayList<>();
        }

        List<TrainingItemVo> vos = CopyUtils.copyList(result, TrainingItemVo.class);
        for (TrainingItemVo vo : vos) {
            vo.setType((byte)1);
        }

        int totalPage = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
        if (pageNo >= totalPage) {
            // 查询了最后一页，找到该课程的进行中考试
            Map<String, Object> queryExamParams = new HashMap<>();
            queryExamParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamPersonDto::getPartyPersonId), partyPerson.getId());
            queryExamParams.put(LambdaUtil.getFieldName(TrainingItemDto::getTrainingId), trainingId);
            queryExamParams.put(LambdaUtil.getFieldName(PartyEducationTrainingExamDto::getStatus), PartyEducationExamConstants.StatusEnum.PUBLISHED.getStatus());
            List<ExamRefPersonDto> examRefPersonDtos = partyEducationTrainingExamPersonService.queryExamList(queryExamParams);
            List<TrainingItemVo> exams = examRefPersonDtos.parallelStream().map(o -> {
                TrainingItemVo trainingItemVo = new TrainingItemVo();
                trainingItemVo.setId(o.getId());
                trainingItemVo.setType((byte)2);
                trainingItemVo.setTakeStatus(o.getTakeStatus());
                trainingItemVo.setName(o.getName());
                return trainingItemVo;
            }).collect(Collectors.toList());
            vos.addAll(exams);
        }

        Page<TrainingItemVo> page = new Page<>(request.getPageNo(), request.getPageSize(), total, vos);
        return Response.<Page<TrainingItemVo>>ok().wrap(page);
    }

    @GetMapping("commentList")
    @Operation(summary = "评价信息列表")
    public Response<Page<TrainingCommentDto>> trainingCommentList(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize,
            @Parameter(description = "课程id") @RequestParam Long trainingId
    ) {
        // query trainingComment by trainingId
        SessionHolder.checkPartyPerson();

        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        int total = trainingCommentService.queryTotal(request.getParams());
        List<TrainingCommentDto> result = null;
        if (total > 0) {
            result = trainingCommentService.queryList(request.getParams());
        } else {
            result = new ArrayList<>();
        }

        Page<TrainingCommentDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, result);
        return Response.<Page<TrainingCommentDto>>ok().wrap(page);
    }

    @GetMapping("experienceInfo")
    @Operation(summary = "课程心得详情")
    public Response<TrainingExperienceDto> experienceInfo(
            @Parameter(description = "课程id") @RequestParam Long trainingId
    ) {
        // query trainingExperience by trainingId
        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        TrainingExperienceDto oldOne = trainingExperienceService.selectOne(partyPerson.getId(), trainingId);

        return Response.<TrainingExperienceDto>ok().wrap(oldOne);
    }

    @GetMapping("commentInfo")
    @Operation(summary = "课程评价详情")
    public Response<TrainingCommentDto> commentInfo(
            @Parameter(description = "课程id") @RequestParam Long trainingId
    ) {
        // query trainingExperience by trainingId
        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        TrainingCommentDto oldOne = trainingCommentService.selectOne(partyPerson.getId(), trainingId);
        return Response.<TrainingCommentDto>ok().wrap(oldOne);
    }

    @PostMapping("appraise")
    @Operation(summary = "课程评价")
    public Response<Object> appraise(@RequestBody @Validated CommentAppraiseReqVo commentAppraiseVo) {
        // add trainingComment
        // update training commentCount

        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        Map<String, Object> params = new HashMap<>();
        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getPartyPersonId), partyPerson.getId());
        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getTrainingId), commentAppraiseVo.getTrainingId());
        if (trainingPersonService.queryTrainingTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        TrainingCommentDto oldOne = trainingCommentService.selectOne(partyPerson.getId(), commentAppraiseVo.getTrainingId());
        if (Objects.nonNull(oldOne)) {
            return Response.error("该课程已经提交过评价");
        }

        TrainingDto trainingDto = trainingService.selectCacheById(commentAppraiseVo.getTrainingId());
        TrainingCommentDto trainingCommentDto = new TrainingCommentDto();
        trainingCommentDto.setTenantId(trainingDto.getTenantId());
        trainingCommentDto.setPartyId(trainingDto.getPartyId());
        trainingCommentDto.setTrainingId(trainingDto.getId());
        trainingCommentDto.setPartyPersonId(partyPerson.getId());
        trainingCommentDto.setScore(commentAppraiseVo.getScore());
        trainingCommentDto.setContent(commentAppraiseVo.getContent());
        trainingCommentDto.setCreateTime(new Date());
        trainingCommentService.saveAndUpdate(trainingCommentDto);
        return Response.ok();
    }

    @PostMapping("experience")
    @Operation(summary = "课程心得")
    public Response<Object> experience(@RequestBody @Validated ExperienceAppraiseReqVo experienceAppraiseReqVo) {
        // add trainingComment
        // update training commentCount

        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        Map<String, Object> params = new HashMap<>();
        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getPartyPersonId), partyPerson.getId());
        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getTrainingId), experienceAppraiseReqVo.getTrainingId());
        if (trainingPersonService.queryTrainingTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        TrainingExperienceDto oldOne = trainingExperienceService.selectOne(partyPerson.getId(), experienceAppraiseReqVo.getTrainingId());
        if (Objects.nonNull(oldOne)) {
            return Response.error("该课程已经提交过心得");
        }

        TrainingDto trainingDto = trainingService.selectCacheById(experienceAppraiseReqVo.getTrainingId());
        TrainingExperienceDto trainingExperienceDto = new TrainingExperienceDto();
        trainingExperienceDto.setTenantId(trainingDto.getTenantId());
        trainingExperienceDto.setPartyId(trainingDto.getPartyId());
        trainingExperienceDto.setTrainingId(trainingDto.getId());
        trainingExperienceDto.setPartyPersonId(partyPerson.getId());
        trainingExperienceDto.setTitle(experienceAppraiseReqVo.getTitle());
        trainingExperienceDto.setContent(experienceAppraiseReqVo.getContent());
        trainingExperienceDto.setCreateTime(new Date());
        trainingExperienceService.saveAndUpdate(trainingExperienceDto);
        return Response.ok();
    }

//    @GetMapping("getProgress")
//    @Operation(summary = "获取学习进度")
//    public Response<TrainingDto> getProgress(
//            @Parameter(description = "课时id") @RequestParam Long trainingItemId
//    ){
//        super.checkEmp();
//        DeptPersonDto emp = super.getEmp();
//
//        TrainingItemPersonDto trainingItemPersonDto = trainingItemPersonService.selectOne(trainingItemId, emp.getId());
//        StudyProgressRespVo resp = StudyProgressRespVo.newNotLearnedObj();
//        if (trainingItemPersonDto != null) {
//            resp.setStudyStatus(trainingItemPersonDto.getStudyStatus());
//            resp.setStudyProgress(trainingItemPersonDto.getStudyProgress() == null
//                    ? BigDecimal.ZERO : trainingItemPersonDto.getStudyProgress());
//        }
//        return Response.ok().wrap(resp);
//    }

    @PostMapping("study")
    @Operation(summary = "课时学习")
    public Response<Object> study(@RequestBody @Validated TrainingItemStudyReqVo trainingItemStudyVo) {
        // add trainingItemPerson or update
        SessionHolder.checkPartyPerson();
        PartyPersonDto partyPerson = SessionHolder.getLoginMobileUserSession().getPartyPerson();

        Date currentDate = new Date();

        if (TrainingItemConstants.StudyProgressEnum.ZERO.getStudyProgress().compareTo(trainingItemStudyVo.getStudyProgress()) > 0
                || TrainingItemConstants.StudyProgressEnum.ALL.getStudyProgress().compareTo(trainingItemStudyVo.getStudyProgress()) < 0) {
            return Response.error("参数错误");
        }

        TrainingItemDto trainingItemDto = trainingItemService.selectCacheById(trainingItemStudyVo.getTrainingItemId());
        if (trainingItemDto == null) {
            return Response.error("课时不存在");
        }
        TrainingDto trainingDto = trainingService.selectCacheById(trainingItemDto.getTrainingId());
        if (DateUtil.compare(currentDate, trainingDto.getStartTime()) < 0) {
            return Response.error("课程还未开始");
        }

//        Map<String, Object> params = new HashMap<>();
//        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getDeptPersonId), emp.getId());
//        params.put(LambdaUtil.getFieldName(TrainingPersonDto::getTrainingId), trainingItemDto.getTrainingId());
//        if (trainingPersonService.queryTrainingTotal(params) <= 0) {
//            return Response.error(SystemConstants.ILLEGAL_MSG);
//        }

        if (DateUtil.compare(currentDate, trainingDto.getEndTime()) > 0) {
            // 已经结束的课程直接返回
            return Response.ok();
        }
        TrainingItemPersonDto trainingItemPersonDto = trainingItemPersonService.selectOne(trainingItemDto.getId(), partyPerson.getId());
        if (trainingItemPersonDto != null
                && TrainingItemConstants.StudyStatusEnum.FINISH.getStudyStatus().equals(trainingItemPersonDto.getStudyStatus())) {
            // 已经完成了该课时的学习，直接返回
            return Response.ok();
        }
        if (trainingItemPersonDto != null
                && TrainingItemConstants.StudyProgressEnum.ALL.getStudyProgress().compareTo(trainingItemStudyVo.getStudyProgress()) <= 0) {
            // 上报完成学习的进度，检测是否满足学习时长
            long betweenMinute = DateUtil.between(trainingItemPersonDto.getStartTime(), currentDate, DateUnit.SECOND);
            if (betweenMinute < trainingItemDto.getLearnDuration()) {
                return Response.error("未达到要求的学习时长");
            }
        }

        trainingItemPersonService.study(trainingItemDto.getTrainingId(), trainingItemDto.getId(), partyPerson.getId(), currentDate, trainingItemStudyVo.getStudyProgress());
        return Response.ok();
    }
}
